package pay.portal;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.client.utils.URIBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import pay.base.BaseCtrl;
import pay.base.ResponseBase;
import pay.common.*;
import pay.entity.ErrorLog;
import pay.entity.HistoryPayment;
import pay.entity.Payment;
import pay.entity.SysUser;
import pay.portal.web.message.CommonReq;
import pay.portal.web.message.CommonRes;
import pay.portal.web.message.ap;
import pay.service.*;
import pay.service.sys.ISysUser;
import pay.utils.BeanAndXMLTurn;
import pay.utils.CacheConstants;
import pay.utils.DateUtil;
import pay.utils.EncryptDecryptUtils;
import pay.utils.FYApiUtil;
import pay.utils.MapSortUtil;
import pay.utils.RedisCilent;
import pay.utils.SecurityUtils;
import pay.utils.StringHelper;
import pay.utils.WriteFileUtils;

@Controller
@EnableAutoConfiguration
@RequestMapping(value = BaseCtrl.App)
public class CreateAccount_httpCtrl extends BaseCtrl {

	/**
	 * 商户代码，从配置文件中读取
	 */
	@Value("${fy.mchntCd}")
	private String mchnt_cd;

	@Value("${server.scheme}")
	private String serverScheme;

	@Value("${fy.goldAccount.logsBaseUrl}")
	private String logBaseUrl;
	
	@Value("${fy.goldAccount.pathBaseUrl}")
	private String pathBaseUrl;// 测试环境为/jzh 生产无。
	/**
	 * 商户密钥，从配置文件中读取
	 */
	// @Value("${fy.Secret}")
	// private String secret;
	@Value("${pc.secret}")
	private String pcSecret;
	@Value("${server.url}")
	private String serverUrl;

	/**
	 * 金账户baseURl，从配置文件中读取
	 */
	@Value("${fy.goldAccount.baseUrl}")
	private String jzhBaseUrl;

	@Autowired
	private IFYResultCode fyResultCodeService;

	@Autowired
	private IPayment paymentService;

	@Autowired
	private IHistoryPayment historyPaymentService;
	
	@Autowired
	private ISysUser sysUserService;

	@Autowired
	private IErrorLogJPA errorLogJPA;

	@Autowired
	private ChangeCardService changeCardService;

    /**
     * 富友换卡t+1日审核完毕后的通知接口
     *
     * @param request
     */
    @ResponseBody
    @RequestMapping(value = "/changeCardSuccCallBack", method = RequestMethod.POST)
    public void changeCardSuccCallBack(HttpServletRequest request) {
        // 富有换卡成功
        String mchnt_cd = request.getParameter("mchnt_cd");
        String email = request.getParameter("email");
        String signature = request.getParameter("signature");
        String user_id_from = request.getParameter("user_id_from");

        String mchnt_txn_ssn = request.getParameter("mchnt_txn_ssn");
        String mobile_no = request.getParameter("mobile_no");
        String cust_nm = request.getParameter("cust_nm");// 客户姓名
        String certif_id = request.getParameter("certif_id");// 身份证
        String city_id = request.getParameter("city_id");
        String parent_bank_id = request.getParameter("parent_bank_id");
        String bank_nm = request.getParameter("bank_nm");
        String capAcntNo = request.getParameter("capAcntNo");// 卡号
        String resp_code = request.getParameter("resp_code");
        logger.info(
                "换卡审核成功后回调入参mchnt_cd={},email={},user_id_from={},mchnt_txn_ssn={},mobile_no={},cust_nm={},certif_id={},city_id={},parent_bank_id={},bank_nm={},capAcntNo={},resp_code={},signature={}",
                mchnt_cd, email, user_id_from, mchnt_txn_ssn, mobile_no,
                cust_nm, certif_id, city_id, parent_bank_id, bank_nm,
                capAcntNo, resp_code, signature);
        String baseURL = bank_nm + "|" + capAcntNo + "|" + certif_id + "|"
                + city_id + "|" + cust_nm + "|" + email + "|" + mchnt_cd + "|"
                + mchnt_txn_ssn + "|" + mobile_no + "|" + parent_bank_id + "|"
                + resp_code + "|" + user_id_from;

        logger.info("华康加密明文：baseURL={}", baseURL);

        if (!SecurityUtils.verifySign(baseURL, signature)) {
            logger.info("非法请求！sign不匹配！");
            return;
        }

        try {
            cust_nm = URLDecoder.decode(cust_nm, "UTF-8");
            writeChangeSuccessCardToFile(mchnt_txn_ssn, mobile_no, cust_nm, certif_id, city_id, parent_bank_id, bank_nm, capAcntNo, resp_code);

            HqlFilter userFilter = new HqlFilter();
            userFilter.addEQFilter("name", mobile_no);
            userFilter.addEQFilter("closeAccount", ConstantUser.NOT_CLOSE_ACCOUNT);
            List<SysUser> userList = sysUserService.findByFilter(userFilter);
            if (userList.size() <= 0)
            {
                logger.info("不存在该用户！手机号mobile_no={}", mobile_no);
                return;
            }

            SysUser user = userList.get(0);

            HqlFilter paymentFilter = new HqlFilter();
            paymentFilter.addEQFilter("userRegistPhone", mobile_no);
            paymentFilter.addEQFilter("cardStatus", CardStatusCode.FY_CHANGE_CARDING);
            List<Payment> userChangePaymentList = paymentService.findByFilter(paymentFilter);

            // 有换卡请求记录则换卡
            if (userChangePaymentList.size() > 0) {
                changeCardService.updateAppChangeCardResult(mobile_no, cust_nm, certif_id, capAcntNo, user, userChangePaymentList);
            }

            // 处理在富有后台独自换卡的情况
            if (userChangePaymentList.size() <= 0) {
                handle_FY_BackEnd_ChangeCardCase(mchnt_txn_ssn, capAcntNo, resp_code, user,mobile_no, cust_nm, certif_id);
            }

            updateUserInfoFromBankCard(cust_nm, certif_id, user);

        } catch (Exception e) {
            logger.error("富友换卡审核成功回调函数异常！{}", e);
        }

    }

    private void updateUserInfoFromBankCard(String cust_nm, String certif_id, SysUser user) {
        if (StringHelper.isEmpty(user.getIdentity())
                || StringHelper.isEmpty(user.getRealName())) {
            sysUserService.upUserByPayment(user.getId(), null,
                    certif_id, cust_nm, ConstantPayment.HAS_FYACCOUNT);
        }
    }

    private void handle_FY_BackEnd_ChangeCardCase(String mchnt_txn_ssn, String capAcntNo, String resp_code, SysUser user,
                                                  String mobile_no,String cust_nm, String certif_id) {

        Long userId = user.getId();

        logger.info("该用户不存在App发起的换卡请求，userId={} mchnt_txn_ssn={}", userId,mchnt_txn_ssn);

        List<Payment> existingPayments = changeCardService.getExistingPayments(capAcntNo);

        if (existingPayments.size() > 0) {
            logger.info("该用户Id({}) 已经用过银行卡({}), 不能再换. mchnt_txn_ssn={}", userId,capAcntNo,mchnt_txn_ssn);
            return;
        }

        changeCardService.syncCardFromOnlyFYBackEndChange(resp_code, mchnt_txn_ssn, user,mobile_no,cust_nm,certif_id,capAcntNo);
    }


    private void writeChangeSuccessCardToFile(String mchnt_txn_ssn, String mobile_no, String cust_nm, String certif_id, String city_id, String parent_bank_id, String bank_nm, String capAcntNo, String resp_code) {
        Long cts = System.currentTimeMillis();
        String log = DateUtil.transferLongToDate("yyyy-MM-dd HH:mm:ss",
                cts)
                + "----换卡审核成功后回调入参:  mchnt_txn_ssn = "
                + mchnt_txn_ssn
                + ",mobile_no = "
                + mobile_no
                + ",cust_nm = "
                + cust_nm
                + ",certif_id = "
                + certif_id
                + ",city_id = "
                + city_id
                + ",parent_bank_id = "
                + parent_bank_id
                + ",bank_nm = "
                + bank_nm
                + ",capAcntNo = "
                + capAcntNo
                + ",resp_code = "
                + resp_code + "\r\n";
        WriteFileUtils.writeFile("ChangeCardRecordSucc-", "yyyyMM", logBaseUrl +
                        "/payServerRecords/ChangeCardRecords/", log,
                cts);
    }



    /**
	 * 富友换卡回调函数入口
	 * 
	 * @param request
	 */
	@ResponseBody
	@RequestMapping(value = "/FYChangeCardCallBack", method = RequestMethod.POST)
    public void FYChangeCardCallBack(HttpServletRequest request,
                                     HttpServletResponse response) {

        String resp_code = request.getParameter("resp_code");
        String mchnt_txn_ssn = request.getParameter("mchnt_txn_ssn");
        String desc_code = request.getParameter("desc_code");
        logger.info("富友换卡请求回调入参resp_code={},mchnt_txn_ssn={},desc_code={}",
                resp_code, mchnt_txn_ssn, desc_code);

        changeCardService.syncCardToChangeStatus(resp_code, mchnt_txn_ssn);

        changeCardService.writeChangeCardResultToFile(resp_code, mchnt_txn_ssn, desc_code);

        try {
            // http://59.107.26.181/mobile/changeCardResult.html
            String responseMsg = "系统换卡异常";
            try {
                responseMsg = fyResultCodeService.getCodeMsg(resp_code);
            } catch (Exception e) {
                logger.error("获取错误码异常!", e);
            }

            responseMsg = URLEncoder.encode(responseMsg, "utf-8");
            response.sendRedirect(serverScheme + "://" + serverUrl
                    + "/pays/changeCardResult.html?responseMsg="
                    + responseMsg);
        } catch (IOException e) {
            logger.error("富友换卡回调函数入口error:{}", e);
        }
    }




    private boolean checkToken(String token, String userId) {
		boolean t = false;
		if (RedisCilent.existsKey(CacheConstants.VALIDATE_TOKEN + token)) {
			String cacheUserId = RedisCilent
					.getString(CacheConstants.VALIDATE_TOKEN + token);
			if (userId.equals(cacheUserId)) {
				t = true;
				RedisCilent.delKey(CacheConstants.VALIDATE_TOKEN + token);
			}
		}
		return t;
	}

	@ResponseBody
	@RequestMapping(value = "/kaihu", produces = "application/json;charset=UTF8", method = RequestMethod.POST)
	public ResponseBase<CommonRes> FYKaihuHttp(@RequestBody CommonReq req) {
		logger.info("进入8082富友开户接口");
		ResponseBase<CommonRes> responseBase = new ResponseBase<CommonRes>();
		String userId = req.getUserId();
		String bank_nm = ""; // 开户行支行名称 ： 非强制
		String capAcntNo = req.getCapAcntNo();// 银行卡帐号：强制
		String capAcntNm = "";// 账户名： 非强制
		String certif_id = req.getCertif_id();// 身份证号 ：强制
		String city_id = req.getCity_id();// 开户行地区代码 ：强制
		String cust_nm = req.getCust_nm();// 客户姓名 : 强制
		try {
			cust_nm = URLDecoder.decode(cust_nm, "UTF-8");
		} catch (UnsupportedEncodingException e1) {
			logger.error("姓名转换异常！", e1);
		}
		String email = "";// 邮箱 : 非强制

		String mobile_no = req.getMobile_no(); // 手机号 : 强制
		String mchnt_txn_ssn = mobile_no
				+ String.valueOf(System.currentTimeMillis());// 流水号
		String parent_bank_id = req.getParent_bank_id();// 开户行行别 : 强制
		String lpassword = "";// 登录密码 :非强制
		String password = req.getPassword(); // 体现密码 :强制
		String rem = "";// 备注 :非强制
		String certif_tp = "0";// 证件类型 : 强制
		String token = req.getToken();
		String sign = req.getSign();
		String innerParams = "富友绑卡方法关键入参mobile_no=" + mobile_no + "&capAcntNo="
				+ capAcntNo + "&cust_nm=" + cust_nm + "&certif_id=" + certif_id
				+ "&userId=" + userId + "&password=" + password + "&token="
				+ token;
		logger.info(
				"进入富友绑卡方法关键入参mobile_no={},capAcntNo={},cust_nm={},certif_id={},userId={},password={},token={}",
				mobile_no, capAcntNo, cust_nm, certif_id, userId, password,
				token);
		try {
			Long cts = System.currentTimeMillis();
			String log = DateUtil
					.transferLongToDate("yyyy-MM-dd HH:mm:ss", cts)
					+ "----富友用户开户传入绑卡信息:  certif_id = "
					+ certif_id
					+ ",cust_nm = "
					+ cust_nm
					+ ",capAcntNo = "
					+ capAcntNo
					+ ",mobile_no = "
					+ mobile_no
					+ ",city_id="
					+ city_id
					+ ",parent_bank_id="
					+ parent_bank_id
					+ ",userId ="
					+ userId + "\r\n";
			WriteFileUtils.writeFile("AddCardRecord-", "yyyyMM",logBaseUrl+
					"/payServerRecords/AddCardLogRecord/", log, cts);

		} catch (Exception e) {
			logger.error("写绑卡文本文件失败！", e);
		}
		if (StringHelper.isEmpty(mobile_no) || StringHelper.isEmpty(capAcntNo)
				|| StringHelper.isEmpty(cust_nm)
				|| StringHelper.isEmpty(certif_id)
				|| StringHelper.isEmpty(userId) || StringHelper.isEmpty(token)
				|| StringHelper.isEmpty(password)) {
			logger.info("入参有空参数");
			String errorMsg = ResultCode.PARAM_LACK.getMsg();
			responseBase.setMsg(errorMsg);
			responseBase.setResultCode(ResultCode.PARAM_LACK.getCode());
			addErrorMsg(cust_nm, Long.parseLong(userId), errorMsg, innerParams,null);
			return responseBase;
		}
		Map<String, String> map = getRequestMap(userId, capAcntNo, certif_id,
				city_id, cust_nm, mobile_no, parent_bank_id, password, token,
				sign);

		boolean b = EncryptDecryptUtils.validateSignByMap(pcSecret, map);

		if (b) {// 校验请求签名
			if (!checkToken(token, userId)) {// 校验幂等请求
				logger.info("token:{}  is not exits", token);
				String errorMsg = ResultCode.ILLEGAL_TOKEN.getMsg();
				responseBase.setMsg(errorMsg);
				responseBase.setResultCode(ResultCode.ILLEGAL_TOKEN.getCode());
				addErrorMsg(cust_nm, Long.parseLong(userId), errorMsg,
						innerParams,null);
				return responseBase;
			}

			SysUser user = sysUserService.findById(Long.parseLong(userId));
			if (user == null) {
				logger.info("该用户不存在！userId={}", userId);
				String errorMsg = ResultCode.USER_NOT_EXIST.getMsg();
				responseBase.setMsg(errorMsg);
				responseBase.setResultCode(ResultCode.USER_NOT_EXIST.getCode());
				addErrorMsg(cust_nm, Long.parseLong(userId), errorMsg,
						innerParams,null);
				return responseBase;
			}

			if (StringHelper.isNotEmpty(user.getIdentity())
					&& StringHelper.isNotEmpty(certif_id)) {
				if (!(certif_id.compareToIgnoreCase(user.getIdentity())==0)) {
					logger.info("用户身份证和绑卡填写的身份证不一致!用户身份证={},certif_id={}",
							user.getIdentity(), certif_id);
					String errorMsg = "用户身份证和绑卡填写的身份证不一致！";
					responseBase.setMsg(errorMsg);
					responseBase.setResultCode("1008");
					addErrorMsg(cust_nm, Long.parseLong(userId), errorMsg,
							innerParams,null);
					return responseBase;
				}
			}
			/******************************************* 校验完毕 ****************************************************/

			/************************************************* 富友开户 ****************************************************/
			/* 富友有判断重复的卡，同一商户，银行卡、身份证、手机号全都要唯一。 */
			String openResult = sendPostToFY(certif_tp, bank_nm, capAcntNm,
					capAcntNo, certif_id, city_id, cust_nm, email, lpassword,
					mchnt_txn_ssn, mobile_no, parent_bank_id, password, rem);
			try {
				Long cts = System.currentTimeMillis();
				String log = DateUtil.transferLongToDate("yyyy-MM-dd HH:mm:ss",
						cts) + "----富友开户返回结果:  " + openResult + "\r\n";
				WriteFileUtils.writeFile("AddCardRecord-", "yyyyMM",logBaseUrl+
						"/payServerRecords/AddCardLogRecord/", log,
						cts);
			} catch (Exception e) {
				logger.error("写绑卡文本文件失败！", e);
			}
			if ("-1111".equals(openResult)) {
				responseBase.setResultCode(ResultCode.FAILED.getCode());
				responseBase.setMsg("开户异常");
				addErrorMsg(cust_nm, Long.parseLong(userId), "开户异常",
						innerParams,null);
				logger.info("开户异常！卡号capAcntNo={}", capAcntNo);
			} else {
				BeanAndXMLTurn<ap> ff = new BeanAndXMLTurn<ap>();
				ap fmresultFm = ff.XMLStringToBean(openResult, new ap());
				String responseCode = fmresultFm.getPlain().getResp_code();
				String mchntTxnSsn=fmresultFm.getPlain().getMchnt_txn_ssn();
				if ("0000".equals(responseCode)) {
					// 关联更新用户个人身份证号和真实姓名
					try {
						sysUserService.upUserByPayment(Long.parseLong(userId),
								null, certif_id, cust_nm,ConstantPayment.HAS_FYACCOUNT);
					} catch (Exception e) {
						logger.error("关联更新用户身份证号和姓名异常", e);
					}
					user = sysUserService.findById(Long.parseLong(userId));
					Payment newPayment=paymentService.addOrUpdatePayment(capAcntNo, cust_nm,
							certif_id, mobile_no, user);
					try {
						HistoryPayment historyPayment=new HistoryPayment();
						historyPayment.setCompany(ConstantRoute.COMPANY_HUAKANG);
						historyPayment.setPaymentType(CardStatusCode.PAYMENT_TYPE_ADD);
						historyPayment.setNewBankNo(capAcntNo);
						historyPayment.setNewBankName(newPayment.getBankName());
						historyPayment.setUserId(user.getId());
						historyPayment.setPaymentId(newPayment.getId());
						historyPayment.setStatus(1);
						historyPaymentService.add(historyPayment);
						//historyPaymentService.add(ConstantRoute.COMPANY_HUAKANG, CardStatusCode.PAYMENT_TYPE_ADD, null, capAcntNo, user.getId());					
					} catch (Exception e) {
						logger.info("<-------------------------ERROR------------------------>");
						logger.error("富友绑卡添加到解绑卡历史表异常!!",e);
					}
					user.setTieCard(CardStatusCode.PAYMENT_DISPLAY_SHOW);
					sysUserService.update(user);
					CommonRes result = new CommonRes();
					result.setBank_Code(parent_bank_id);
					result.setBank_No(capAcntNo);
					result.setCertif_No(certif_id);
					result.setCust_Name(cust_nm);
					responseBase.setResultCode(ResultCode.SUCC.getCode());
					responseBase.setMsg("开户成功");
					responseBase.setResult(result);
				} else if ("5138".equals(responseCode)) {
					try {
						RedisCilent.listSet(CacheConstants.CREATEACCOUNT,
								mobile_no);
					} catch (Exception e) {
						logger.error("开户超时手机号放入缓存异常！", e);
					}
				} else {
					String errorMsg = fyResultCodeService
							.getCodeMsg(responseCode);
					logger.info(
							"该用户开户返回结果为responseCode={},errorMsg={},userId={}",
							responseCode, errorMsg, userId);
					responseBase.setResultCode(responseCode);
					responseBase.setMsg(errorMsg);
					if (StringHelper.isEmpty(responseBase.getMsg())) {
						responseBase.setMsg("开户失败，请重新校验输入信息！");
					}
					addErrorMsg(cust_nm, Long.parseLong(userId), errorMsg,
							innerParams,mchntTxnSsn);
				}
			}
		} else {
			responseBase.setResultCode(ResultCode.IREECT_SIGN.getCode());
			responseBase.setMsg(ResultCode.IREECT_SIGN.getMsg());
		}
		return responseBase;
	}

	private void addErrorMsg(String accountName, Long userId, String errorMsg,
			String innerParams,String mchntTxnSsn) {
		Long id = System.currentTimeMillis();
		String errorTime = DateUtil.transferLongToDate("yyyyMMddHHmmss",
				System.currentTimeMillis());
		ErrorLog errorLog = new ErrorLog();
		errorLog.setAccountName(accountName);
		errorLog.setErrorMsg(errorMsg);
		errorLog.setErrorTime(errorTime);
		errorLog.setId(id);
		errorLog.setMchntTxnSsn(mchntTxnSsn);
		errorLog.setInnerParams(innerParams);
		errorLog.setUserId(userId);
		errorLogJPA.save(errorLog);
	}

	private String sendPostToFY(String certif_tp, String bank_nm,
			String capAcntNm, String capAcntNo, String certif_id,
			String city_id, String cust_nm, String email, String lpassword,
			String mchnt_txn_ssn, String mobile_no, String parent_bank_id,
			String password, String rem) {
		String pathUrl = pathBaseUrl + "/reg.action";
		// https://jzh-test.fuiou.com/jzh/reg.action
		URIBuilder builder = new URIBuilder().setScheme("https")
				.setHost(jzhBaseUrl).setPath(pathUrl);
		logger.info(builder.toString());
		Map<String, String> trimmedParams = new HashMap<>();
		String allUrl = bank_nm + "|" + capAcntNm + "|" + capAcntNo + "|"
				+ certif_id + "|" + city_id + "|" + cust_nm + "|" + email + "|"
				+ lpassword + "|" + mchnt_cd + "|" + mchnt_txn_ssn + "|"
				+ mobile_no + "|" + parent_bank_id + "|" + password + "|" + rem;

		SecurityUtils.initPrivateKey();
		SecurityUtils.initPublicKey();
		String signature = SecurityUtils.sign(allUrl);

		logger.info("富友绑卡卡号：" + capAcntNo + "流水号:" + mchnt_txn_ssn + "明文:"
				+ allUrl + "签名：" + signature);

		trimmedParams.put("mchnt_cd", mchnt_cd);
		trimmedParams.put("mchnt_txn_ssn", mchnt_txn_ssn);
		trimmedParams.put("cust_nm", cust_nm);
		trimmedParams.put("certif_tp", certif_tp);
		trimmedParams.put("certif_id", certif_id);
		trimmedParams.put("mobile_no", mobile_no);
		trimmedParams.put("city_id", city_id);
		trimmedParams.put("parent_bank_id", parent_bank_id);
		trimmedParams.put("capAcntNo", capAcntNo);
		trimmedParams.put("signature", signature);
		trimmedParams.put("password", password);
		String openResult = FYApiUtil.doPost(builder, trimmedParams);
		return openResult;
	}

	private Map<String, String> getRequestMap(String userId, String capAcntNo,
			String certif_id, String city_id, String cust_nm, String mobile_no,
			String parent_bank_id, String password, String token, String sign) {

		Map<String, String> map = new HashMap<String, String>();
		map.put("userId", userId);
		map.put("capAcntNo", capAcntNo);
		map.put("certif_id", certif_id);
		map.put("city_id", city_id);
		map.put("cust_nm", cust_nm.length() + "");
		map.put("mobile_no", mobile_no);
		map.put("parent_bank_id", parent_bank_id);
		map.put("token", token);
		map.put("sign", sign);
		map.put("password", password);
		map = MapSortUtil.sortMapByKey(map);
		return map;

	}
}
